home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcl / src-16f.lha / compiler / constraint.lisp < prev    next >
Encoding:
Text File  |  1992-07-28  |  15.9 KB  |  519 lines

  1. ;;; -*- Package: C; Log: C.Log -*-
  2. ;;;
  3. ;;; **********************************************************************
  4. ;;; This code was written as part of the CMU Common Lisp project at
  5. ;;; Carnegie Mellon University, and has been placed in the public domain.
  6. ;;; If you want to use this code or any part of CMU Common Lisp, please contact
  7. ;;; Scott Fahlman or slisp-group@cs.cmu.edu.
  8. ;;;
  9. (ext:file-comment
  10.   "$Header: constraint.lisp,v 1.13 92/06/03 20:03:37 ram Exp $")
  11. ;;;
  12. ;;; **********************************************************************
  13. ;;;
  14. ;;;    This file implements the constraint propagation phase of the compiler,
  15. ;;; which uses global flow analysis to obtain dynamic type information.
  16. ;;; 
  17. ;;; Written by Rob MacLachlan
  18. ;;;
  19. (in-package 'c)
  20.  
  21. (defstruct (constraint
  22.         (:include sset-element)
  23.         (:constructor make-constraint (number kind x y not-p)))
  24.   ;;
  25.   ;; The kind of constraint we have:
  26.   ;;     
  27.   ;; TYPEP
  28.   ;;     X is a LAMBDA-VAR and Y is a CTYPE.  The value of X is constrained to
  29.   ;;     be of type Y.
  30.   ;;
  31.   ;; >, <
  32.   ;;     X is a lambda-var and Y is a CTYPE.  The relation holds between X and
  33.   ;;     some object of type Y.
  34.   ;;
  35.   ;; EQL
  36.   ;;     X is a LAMBDA-VAR Y is a LAMBDA-VAR or a CONSTANT.  The relation is
  37.   ;;     asserted to hold.
  38.   ;;
  39.   (kind nil :type (member typep < > eql))
  40.   ;;
  41.   ;; The operands to the relation.
  42.   (x nil :type lambda-var)
  43.   (y nil :type (or ctype lambda-var constant))
  44.   ;;
  45.   ;; If true, negates the sense of the constraint.  The relation is does *not*
  46.   ;; hold.
  47.   (not-p nil :type boolean))
  48.  
  49.  
  50. (defvar *constraint-number*)
  51.  
  52. ;;; FIND-CONSTRAINT  --  Interface
  53. ;;;
  54. ;;;    Return a constraint for the specified arguments.  We only create a new
  55. ;;; constraint if there isn't already an equivalent old one, guaranteeing that
  56. ;;; all equivalent constraints are EQ.  This shouldn't be called on lambda-vars
  57. ;;; with no CONSTRAINTS set.
  58. ;;;
  59. (defun find-constraint (kind x y not-p)
  60.   (declare (type lambda-var x) (type (or constant lambda-var ctype) y)
  61.        (type boolean not-p))
  62.   (or (etypecase y
  63.     (ctype
  64.      (do-elements (con (lambda-var-constraints x) nil)
  65.        (when (and (eq (constraint-kind con) kind)
  66.               (eq (constraint-not-p con) not-p)
  67.               (type= (constraint-y con) y))
  68.          (return con))))
  69.     (constant
  70.      (do-elements (con (lambda-var-constraints x) nil)
  71.        (when (and (eq (constraint-kind con) kind)
  72.               (eq (constraint-not-p con) not-p)
  73.               (eq (constraint-y con) y))
  74.          (return con))))
  75.     (lambda-var 
  76.      (do-elements (con (lambda-var-constraints x) nil)
  77.        (when (and (eq (constraint-kind con) kind)
  78.               (eq (constraint-not-p con) not-p)
  79.               (let ((cx (constraint-x con)))
  80.             (eq (if (eq cx x)
  81.                 (constraint-y con)
  82.                 cx)
  83.                 y)))
  84.          (return con)))))
  85.       (let ((new (make-constraint (incf *constraint-number*) kind x y not-p)))
  86.     (sset-adjoin new (lambda-var-constraints x))
  87.     (when (lambda-var-p y)
  88.       (sset-adjoin new (lambda-var-constraints y)))
  89.     new)))
  90.  
  91.  
  92. ;;; OK-REF-LAMBDA-VAR  --  Internal
  93. ;;;
  94. ;;;    If Ref is to a Lambda-Var with Constraints (i.e. we can do flow analysis
  95. ;;; on it), then return the Lambda-Var, otherwise NIL.
  96. ;;;
  97. (proclaim '(inline ok-ref-lambda-var))
  98. (defun ok-ref-lambda-var (ref)
  99.   (declare (type ref ref))
  100.   (let ((leaf (ref-leaf ref)))
  101.     (when (and (lambda-var-p leaf)
  102.            (lambda-var-constraints leaf))
  103.       leaf)))
  104.  
  105.  
  106. ;;; OK-CONT-LAMBDA-VAR  --  Internal
  107. ;;;
  108. ;;;    If Cont's Use is a Ref, then return OK-REF-LAMBDA-VAR of the Use,
  109. ;;; otherwise NIL.
  110. ;;;
  111. (proclaim '(inline ok-cont-lambda-var))
  112. (defun ok-cont-lambda-var (cont)
  113.   (declare (type continuation cont))
  114.   (let ((use (continuation-use cont)))
  115.     (when (ref-p use)
  116.       (ok-ref-lambda-var use))))
  117.  
  118.  
  119. ;;; ADD-TEST-CONSTRAINT  --  Internal
  120. ;;;
  121. ;;;    Add the indicated test constraint to Block, marking the block as having
  122. ;;; a new assertion when the constriant was not already present.  We don't add
  123. ;;; the constraint if the block has multiple predecessors, since it only holds
  124. ;;; on this particular path.
  125. ;;;
  126. (defun add-test-constraint (block fun x y not-p)
  127.   (unless (rest (block-pred block))
  128.     (let ((con (find-constraint fun x y not-p))
  129.       (old (or (block-test-constraint block)
  130.            (setf (block-test-constraint block) (make-sset)))))
  131.       (when (sset-adjoin con old)
  132.     (setf (block-type-asserted block) t))))
  133.   (undefined-value))
  134.  
  135.  
  136. ;;; ADD-COMPLEMENT-CONSTRAINTS  --  Internal
  137. ;;;
  138. ;;;    Add complementary constraints to the consequent and alternative blocks
  139. ;;; of If.  We do nothing if X is NIL.
  140. ;;;
  141. (proclaim '(inline add-complement-constraints))
  142. (defun add-complement-constraints (if fun x y not-p)
  143.   (when x
  144.     (add-test-constraint (if-consequent if) fun x y not-p)
  145.     (add-test-constraint (if-alternative if) fun x y (not not-p)))
  146.   (undefined-value))
  147.  
  148.  
  149. ;;; ADD-TEST-CONSTRAINTS  --  Internal
  150. ;;;
  151. ;;;    Add test constraints to the consequent and alternative blocks of the
  152. ;;; test represented by Use.
  153. ;;;
  154. (defun add-test-constraints (use if)
  155.   (declare (type node use) (type cif if))
  156.   (typecase use
  157.     (ref
  158.      (add-complement-constraints if 'typep (ok-ref-lambda-var use)
  159.                  *null-type* t))
  160.     (combination
  161.      (let ((name (continuation-function-name
  162.           (basic-combination-fun use)))
  163.        (args (basic-combination-args use)))
  164.        (case name
  165.      (%typep
  166.       (let ((type (second args)))
  167.         (when (constant-continuation-p type)
  168.           (let ((val (continuation-value type)))
  169.           (add-complement-constraints if 'typep
  170.                       (ok-cont-lambda-var (first args))
  171.                       (if (ctype-p val)
  172.                           val
  173.                           (specifier-type val))
  174.                       nil)))))
  175.      ((eq eql)
  176.       (let* ((var1 (ok-cont-lambda-var (first args)))
  177.          (arg2 (second args))
  178.          (var2 (ok-cont-lambda-var arg2)))
  179.         (cond ((not var1))
  180.           (var2
  181.            (add-complement-constraints if 'eql var1 var2 nil))
  182.           ((constant-continuation-p arg2)
  183.            (add-complement-constraints if 'eql var1
  184.                            (ref-leaf
  185.                         (continuation-use arg2))
  186.                            nil)))))
  187.      ((< >)
  188.       (let* ((arg1 (first args))
  189.          (var1 (ok-cont-lambda-var arg1))
  190.          (arg2 (second args))
  191.          (var2 (ok-cont-lambda-var arg2)))
  192.         (when var1
  193.           (add-complement-constraints if name var1 (continuation-type arg2)
  194.                       nil))
  195.         (when var2
  196.           (add-complement-constraints if (if (eq name '<) '> '<)
  197.                       var2 (continuation-type arg1)
  198.                       nil))))
  199.      (t
  200.       (let ((ptype (gethash name (backend-predicate-types *backend*))))
  201.         (when ptype
  202.           (add-complement-constraints if 'typep
  203.                       (ok-cont-lambda-var (first args))
  204.                       ptype nil))))))))
  205.   (undefined-value))
  206.  
  207.           
  208.  
  209. ;;; FIND-TEST-CONSTRAINTS  --  Internal
  210. ;;;
  211. ;;;    Set the Test-Constraint in the successors of Block according to the
  212. ;;; condition it tests.
  213. ;;;
  214. (defun find-test-constraints (block)
  215.   (declare (type cblock block))
  216.   (let ((last (block-last block)))
  217.     (when (if-p last)
  218.       (let ((use (continuation-use (if-test last))))
  219.     (when use
  220.       (add-test-constraints use last)))))
  221.  
  222.   (setf (block-test-modified block) nil)
  223.   (undefined-value))
  224.  
  225.  
  226. ;;; FIND-BLOCK-TYPE-CONSTRAINTS  --  Internal
  227. ;;;
  228. ;;;    Compute the initial flow analysis sets for Block:
  229. ;;; -- For any lambda-var ref with a type check, add that constraint.
  230. ;;; -- For any lambda-var set, delete all constraints on that var, and add
  231. ;;;    those constraints to the set nuked by this block.
  232. ;;;    
  233. (defun find-block-type-constraints (block)
  234.   (declare (type cblock block))
  235.   (let ((gen (make-sset)))
  236.     (collect ((kill nil adjoin))
  237.  
  238.       (let ((test (block-test-constraint block)))
  239.     (when test
  240.       (sset-union gen test)))
  241.       
  242.       (do-nodes (node cont block)
  243.     (typecase node
  244.       (ref
  245.        (when (continuation-type-check cont)
  246.          (let ((var (ok-ref-lambda-var node)))
  247.            (when var
  248.          (let* ((atype (continuation-derived-type cont))
  249.             (con (find-constraint 'typep var atype nil)))
  250.            (sset-adjoin con gen))))))
  251.       (cset
  252.        (let ((var (set-var node)))
  253.          (when (lambda-var-p var)
  254.            (kill var)
  255.            (let ((cons (lambda-var-constraints var)))
  256.          (when cons
  257.            (sset-difference gen cons))))))))
  258.       
  259.       (setf (block-in block) nil)
  260.       (setf (block-gen block) gen)
  261.       (setf (block-kill block) (kill))
  262.       (setf (block-out block) (copy-sset gen))
  263.       (setf (block-type-asserted block) nil)
  264.       (undefined-value))))
  265.  
  266.  
  267. ;;; INTEGER-TYPE-P  --  Internal
  268. ;;;
  269. ;;;    Return true if X is an integer NUMERIC-TYPE.
  270. ;;;
  271. (defun integer-type-p (x)
  272.   (declare (type ctype x))
  273.   (and (numeric-type-p x)
  274.        (eq (numeric-type-class x) 'integer)
  275.        (eq (numeric-type-complexp x) :real)))
  276.  
  277.  
  278. ;;; CONSTRAIN-INTEGER-TYPE  --  Internal
  279. ;;;
  280. ;;;    Given that an inequality holds on values of type X any Y, return a new
  281. ;;; type for X.  If Greater is true, then X was greater than Y, otherwise less.
  282. ;;; If Or-Equal is true, then the inequality was inclusive, i.e. >=.
  283. ;;;
  284. ;;; If Greater (or not), then we max (or min) in Y's lower (or upper) bound
  285. ;;; into X and return that result.  If not Or-Equal, we can go one greater
  286. ;;; (less) than Y's bound.
  287. ;;;
  288. (defun constrain-integer-type (x y greater or-equal)
  289.   (declare (type numeric-type x y))
  290.   (flet ((exclude (x)
  291.        (cond ((not x) nil)
  292.          (or-equal x)
  293.          (greater (1+ x))
  294.          (t (1- x))))
  295.      (bound (x)
  296.        (if greater (numeric-type-low x) (numeric-type-high x))))
  297.     (let* ((x-bound (bound x))
  298.        (y-bound (exclude (bound y)))
  299.        (new-bound (cond ((not x-bound) y-bound)
  300.                 ((not y-bound) x-bound)
  301.                 (greater (max x-bound y-bound))
  302.                 (t (min x-bound y-bound))))
  303.        (res (copy-numeric-type x)))
  304.       (if greater
  305.       (setf (numeric-type-low res) new-bound)
  306.       (setf (numeric-type-high res) new-bound))
  307.       res)))
  308.  
  309.   
  310. ;;; CONSTRAIN-REF-TYPE  --  Internal
  311. ;;;
  312. ;;;    Given the set of Constraints for a variable and the current set of
  313. ;;; restrictions from flow analysis In, set the type for Ref accordingly.
  314. ;;;
  315. (defun constrain-ref-type (ref constraints in)
  316.   (declare (type ref ref) (type sset constraints in))
  317.   (let ((var-cons (copy-sset constraints)))
  318.     (sset-intersection var-cons in)
  319.     (let ((res (single-value-type (node-derived-type ref)))
  320.       (not-res *empty-type*)
  321.       (leaf (ref-leaf ref)))
  322.       (do-elements (con var-cons)
  323.     (let* ((x (constraint-x con))
  324.            (y (constraint-y con))
  325.            (not-p (constraint-not-p con))
  326.            (other (if (eq x leaf) y x))
  327.            (kind (constraint-kind con)))
  328.       (case kind
  329.         (typep
  330.          (if not-p
  331.          (setq not-res (type-union not-res other))
  332.          (setq res (type-intersection res other))))
  333.         (eql
  334.          (let ((other-type (leaf-type other)))
  335.            (if not-p
  336.            (when (and (constant-p other)
  337.                   (member-type-p other-type))
  338.              (setq not-res (type-union not-res other-type)))
  339.            (let ((leaf-type (leaf-type leaf)))
  340.              (when (or (constant-p other)
  341.                    (and (csubtypep other-type leaf-type)
  342.                     (not (type= other-type leaf-type))))
  343.                (change-ref-leaf ref other)
  344.                (when (constant-p other) (return)))))))
  345.         ((< >)
  346.          (when (and (integer-type-p res) (integer-type-p y))
  347.            (let ((greater (eq kind '>)))
  348.          (let ((greater (if not-p (not greater) greater)))
  349.            (setq res
  350.              (constrain-integer-type res y greater not-p)))))))))
  351.       
  352.       (let* ((cont (node-cont ref))
  353.          (dest (continuation-dest cont)))
  354.     (cond ((and (if-p dest)
  355.             (csubtypep *null-type* not-res)
  356.             (eq (continuation-asserted-type cont) *wild-type*))
  357.            (setf (node-derived-type ref) *wild-type*)
  358.            (change-ref-leaf ref (find-constant 't)))
  359.           (t
  360.            (derive-node-type ref (or (type-difference res not-res)
  361.                      res)))))))
  362.  
  363.   (undefined-value))
  364.  
  365.          
  366. ;;; USE-RESULT-CONSTRAINTS  --  Internal
  367. ;;;
  368. ;;;    Deliver the results of constraint propagation to REFs in Block.  During
  369. ;;; this pass, we also do local constraint propagation by adding in constraints
  370. ;;; as we seem them during the pass through the block.
  371. ;;;
  372. (defun use-result-constraints (block)
  373.   (declare (type cblock block))
  374.   (let ((in (block-in block)))
  375.  
  376.     (let ((test (block-test-constraint block)))
  377.       (when test
  378.     (sset-union in test)))
  379.  
  380.     (do-nodes (node cont block)
  381.       (typecase node
  382.     (ref
  383.      (let ((var (ref-leaf node)))
  384.        (when (lambda-var-p var)
  385.          (let ((con (lambda-var-constraints var)))
  386.            (when con
  387.          (constrain-ref-type node con in)
  388.          (when (continuation-type-check cont)
  389.            (sset-adjoin
  390.             (find-constraint 'typep var
  391.                      (continuation-asserted-type cont)
  392.                      nil)
  393.             in)))))))
  394.     (cset
  395.      (let ((var (set-var node)))
  396.        (when (lambda-var-p var)
  397.          (let ((cons (lambda-var-constraints var)))
  398.            (when cons
  399.          (sset-difference in cons))))))))))
  400.  
  401.  
  402. ;;; CLOSURE-VAR-P  --  Internal
  403. ;;;
  404. ;;;    Return true if Var would have to be closed over if environment analysis
  405. ;;; ran now (i.e. if there are any uses that have a different home lambda than
  406. ;;; the var's home.)
  407. ;;;
  408. (defun closure-var-p (var)
  409.   (declare (type lambda-var var))
  410.   (let ((home (lambda-home (lambda-var-home var))))
  411.     (flet ((frob (l)
  412.          (dolist (node l nil)
  413.            (unless (eq (node-home-lambda node) home)
  414.          (return t)))))
  415.       (or (frob (leaf-refs var))
  416.       (frob (basic-var-sets var))))))
  417.  
  418.  
  419. ;;; INIT-VAR-CONSTRAINTS  --  Internal
  420. ;;;
  421. ;;;    Give an empty constraints set to any var that doesn't have one and isn't
  422. ;;; a set closure var.  Since a var that we previously rejected looks identical
  423. ;;; to one that is new, so we optimistically keep hoping that vars stop being
  424. ;;; closed over or lose their sets.
  425. ;;;
  426. (defun init-var-constraints (component)
  427.   (declare (type component component))
  428.   (dolist (fun (component-lambdas component))
  429.     (flet ((frob (x)
  430.          (dolist (var (lambda-vars x))
  431.            (unless (lambda-var-constraints var)
  432.          (when (or (null (lambda-var-sets var))
  433.                (not (closure-var-p var)))
  434.            (setf (lambda-var-constraints var) (make-sset)))))))
  435.       (frob fun)
  436.       (dolist (let (lambda-lets fun))
  437.     (frob let)))))
  438.  
  439.  
  440. ;;; FLOW-PROPAGATE-CONSTRAINTS  --  Internal
  441. ;;;
  442. ;;;    BLOCK-IN becomes the intersection of the OUT of the prececessors.  Our
  443. ;;; OUT is:
  444. ;;;     out U (in - kill)
  445. ;;;
  446. ;;;    BLOCK-KILL is just a list of the lambda-vars killed, so we must compute
  447. ;;; the kill set when there are any vars killed.  We bum this a bit by
  448. ;;; special-casing when only one var is killed, and just using that var's
  449. ;;; constraints as the kill set.  This set could possibly be precomputed, but
  450. ;;; it would have to be invalidated whenever any constraint is added, which
  451. ;;; would be a pain.
  452. ;;;
  453. (defun flow-propagate-constraints (block)
  454.   (let* ((pred (block-pred block))
  455.      (in (cond (pred
  456.             (let ((res (copy-sset (block-out (first pred)))))
  457.               (dolist (b (rest pred))
  458.             (sset-intersection res (block-out b)))
  459.               res))
  460.            (t
  461.             (when *check-consistency*
  462.               (let ((*compiler-error-context* (block-last block)))
  463.             (compiler-warning
  464.              "*** Unreachable code in constraint ~
  465.               propagation...  Bug?")))
  466.             (make-sset))))
  467.      (kill (block-kill block))
  468.      (out (block-out block)))
  469.  
  470.     (setf (block-in block) in)
  471.     (cond ((null kill)
  472.        (sset-union (block-out block) in))
  473.       ((null (rest kill))
  474.        (let ((con (lambda-var-constraints (first kill))))
  475.          (if con
  476.          (sset-union-of-difference out in con)
  477.          (sset-union out in))))
  478.       (t
  479.        (let ((kill-set (make-sset)))
  480.          (dolist (var kill)
  481.            (let ((con (lambda-var-constraints var)))
  482.          (when con
  483.            (sset-union kill-set con))))
  484.          (sset-union-of-difference (block-out block) in kill-set))))))
  485.  
  486.  
  487. ;;; CONSTRAINT-PROPAGATE  --  Interface
  488. ;;;
  489. (defun constraint-propagate (component)
  490.   (declare (type component component))
  491.   (init-var-constraints component)
  492.  
  493.   (do-blocks (block component)
  494.     (when (block-test-modified block)
  495.       (find-test-constraints block)))
  496.  
  497.   (do-blocks (block component)
  498.     (cond ((block-type-asserted block)
  499.        (find-block-type-constraints block))
  500.       (t
  501.        (setf (block-in block) nil)
  502.        (setf (block-out block) (copy-sset (block-gen block))))))
  503.  
  504.   (setf (block-out (component-head component)) (make-sset))
  505.  
  506.   (let ((did-something nil))
  507.     (loop
  508.       (do-blocks (block component)
  509.     (when (flow-propagate-constraints block)
  510.       (setq did-something t)))
  511.  
  512.       (unless did-something (return))
  513.       (setq did-something nil)))
  514.  
  515.   (do-blocks (block component)
  516.     (use-result-constraints block))
  517.  
  518.   (undefined-value))
  519.